/**
 * Copyright (c) 2017-2024 Nop Platform. All rights reserved.
 * Author: canonical_entropy@163.com
 * Blog:   https://www.zhihu.com/people/canonical-entropy
 * Gitee:  https://gitee.com/canonical-entropy/nop-entropy
 * Github: https://github.com/entropy-cloud/nop-entropy
 */
package com.gitee.wsl.struct.table


import com.gitee.wsl.struct.table.utils.CellReferenceHelper
import kotlin.jvm.JvmOverloads

/**
 * 对应一个单元格的位置
 */

class CellPosition(val rowIndex: Int, val colIndex: Int, private val isSystem:Boolean = false) : Comparable<CellPosition> {

    init {
        if(!isSystem){
            if (rowIndex < 0 && colIndex < 0) {
                throw IllegalArgumentException("ERR_TABLE_INVALID_CELL_POSITION row:$rowIndex,col:$colIndex")
                /*.param(ARG_ROW_INDEX, rowIndex)
                .param(
                    ARG_COL_INDEX,
                    colIndex
                )*/
            }

            if (rowIndex >= MAX_ROWS || colIndex >= MAX_COLS)
                throw IllegalArgumentException("ERR_TABLE_INVALID_CELL_POSITION row:$rowIndex,col:$colIndex")
            /*throw NopException(
            ERR_TABLE_INVALID_CELL_POSITION
        ).param(ARG_ROW_INDEX, rowIndex).param(
            ARG_COL_INDEX,
            colIndex
        )*/
        }
    }

    fun offset(x: Int, y: Int): CellPosition {
        return CellPosition(
            if (rowIndex < 0) rowIndex else rowIndex + x,
            if (colIndex < 0) colIndex else colIndex + y
        )
    }

    val isNone: Boolean
        get() = this === NONE

    val isWholeRow: Boolean
        get() = colIndex < 0

    val isWholeCol: Boolean
        get() = rowIndex < 0

    override fun toString(): String {
        return toABString()
    }

    @JvmOverloads
    fun toABString(rowAbs: Boolean = false, colAbs: Boolean = false): String {
        return toABString(rowIndex, colIndex, rowAbs, colAbs)
    }

    fun toRelativeRCString(r: Int, c: Int): String {
        val dr = this.rowIndex - r
        val dc = this.colIndex - c
        val sb = StringBuilder(10)
        if (!isWholeCol) {
            sb.append("R")
            if (dr != 0) {
                sb.append('[')
                sb.append(dr)
                sb.append(']')
            }
        }

        if (!isWholeRow) {
            sb.append("C")
            if (dc != 0) {
                sb.append('[')
                sb.append(dc)
                sb.append(']')
            }
        }
        return sb.toString()
    }

    override fun hashCode(): Int {
        return rowIndex * 31 + colIndex
    }

    override fun equals(other: Any?): Boolean {
        if (other === this) return true

        if (other !is CellPosition) return false
        val pos = other
        return rowIndex == pos.rowIndex && colIndex == pos.colIndex
    }

    override fun compareTo(other: CellPosition): Int {
        if (rowIndex > other.rowIndex) return 1
        if (rowIndex < other.rowIndex) return -1
        if (colIndex > other.colIndex) return 1
        if (colIndex < other.colIndex) return -1
        return 0
    }

    companion object {
        val NONE_NAME: String = "A0"
        val NONE_RC_NAME: String = "R0C0"

        val NONE: CellPosition = CellPosition(-1,-1,true)

        const val MAX_ROWS: Int = 1024 * 1024
        const val MAX_COLS: Int = 65536


        fun fromRCString(str: String): CellPosition? {
            if (NONE_RC_NAME == str) return NONE
            return CellReferenceHelper.parsePositionRCString(str)
        }

        fun fromABString(str: String): CellPosition? {
            return CellReferenceHelper.parsePositionABString(str)
        }

        fun of(rowIndex: Int, colIndex: Int): CellPosition {
            return CellPosition(rowIndex, colIndex)
        }

        fun toRCString(r: Int , c: Int ): String {
            if (r < 0) {
                if (r == -1 && c == -1) return NONE_RC_NAME

                return "C" + (c + 1)
            }
            if (c < 0) return "R" + (r + 1)
            return "R" + (r + 1) + "C" + (c + 1)
        }

        @JvmOverloads
        fun toABString(
            rowIndex: Int,
            colIndex: Int,
            rowAbs: Boolean = false,
            colAbs: Boolean = false
        ): String {
            if (rowIndex == -1 && colIndex == -1) return NONE_NAME

            val sb = StringBuilder(10)
            if (colIndex >= 0) {
                if (colAbs) {
                    sb.append('$')
                }
                sb.append(CellReferenceHelper.convertNumToColString(colIndex))
            }
            if (rowIndex >= 0) {
                if (rowAbs) {
                    sb.append('$')
                }
                sb.append(rowIndex + 1)
            }
            var pos = sb.toString()

            // 单元格下标字符串可以被复用
            /*if (!rowAbs && !colAbs && rowIndex < 100 && colIndex < 50) {
                pos = pos.intern()
            }*/
            return pos
        }
    }
}